home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / ncsat.cpt / Telnet2.5 final / tcpip / tcp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-03  |  19.4 KB  |  706 lines

  1. /*
  2. *   TCP routines
  3. *
  4. ****************************************************************************
  5. *                                                                          *
  6. *      part of:                                                            *
  7. *      TCP/UDP/ICMP/IP Network kernel for NCSA Telnet                      *
  8. *      by Tim Krauskopf                                                    *
  9. *                                                                          *
  10. *      National Center for Supercomputing Applications                     *
  11. *      152 Computing Applications Building                                 *
  12. *      605 E. Springfield Ave.                                             *
  13. *      Champaign, IL  61820                                                *
  14. *                                                                          *
  15. *    Copyright (c) 1987, Board of Trustees of the University of Illinois   *
  16. *                                                                          *
  17. ****************************************************************************
  18. *   Tim Krauskopf       Fall 1986
  19. */
  20. #include <stdio.h>
  21. #include <string.h>
  22.  
  23. #include <Events.h>
  24.  
  25. #include "protocol.h"
  26. #include "data.h"
  27. #include "tools.h"
  28. #include "mactools.h"
  29.  
  30. #define UNKNOWN_PORT_TYPE    0        /* BYU 2.4.16 */
  31. #define MACTCP_PORT_TYPE    1        /* BYU 2.4.16 */
  32. #define NCSA_PORT_TYPE        2        /* BYU 2.4.16 */
  33.  
  34. extern short porttype[];            /* BYU 2.4.16 */
  35.  
  36. extern short slip_connection;    /* BYU 2.4.15 */
  37.  
  38. extern unsigned char SLIP_ip_number[];    /* BYU 2.4.15 */
  39.  
  40. extern uint16 ipcheck
  41.   (
  42.     void *buf,
  43.     long wdcnt                    /* BYU 2.4.8 - was "int" */
  44.   );
  45.  
  46. extern uint16 tcpcheck
  47.   (
  48.     void *phd,
  49.     void *buf,
  50.     long btcnt                    /* BYU 2.4.8 - was "int" */
  51.   );
  52.  
  53. static int pnum;
  54.  
  55. /***************************************************************************/
  56. /*  tcpsend
  57. *     transmits a TCP packet.  
  58. *
  59. *   For IP:
  60. *      sets ident,check,totallen
  61. *   For TCP:
  62. *      sets seq and window from port information,
  63. *        fills in the pseudo header and computes the checksum.
  64. *      Assumes that all fields not filled in here are filled in by the
  65. *      calling proc or were filled in by makeport(). 
  66. *      (see all inits in protinit)
  67. *
  68. */
  69. int tcpsend
  70.   (
  71.     struct port *pport,
  72.     int dlen
  73.   )
  74.     {
  75.     struct port *p;
  76.  
  77.     p = pport;
  78.  
  79.     if (p == NULL) {
  80.         netposterr(404);
  81.         return(-1);
  82.     }
  83.  
  84.     if ((p->type == 1) && slip_connection) {                    /* BYU 2.4.15 */
  85.         movebytes(p->tcpout.i.ipsource,SLIP_ip_number,4);        /* BYU 2.4.15 */
  86.         movebytes(p->tcps.source,SLIP_ip_number,4);                /* BYU 2.4.15 */
  87.     }                                                            /* BYU 2.4.15 */
  88.  
  89. /*
  90. *  do IP header first
  91. */
  92.     p->tcpout.i.ident = intswap(nnipident++);
  93.     p->tcpout.i.tlen = intswap(sizeof(struct iph)+sizeof(struct tcph) + dlen);
  94.     p->tcpout.i.check = 0;                /* install checksum */
  95.     p->tcpout.i.check = ipcheck(&p->tcpout.i,10);
  96. /*
  97. *  do TCP header
  98. */
  99.     p->tcpout.t.seq = longswap(p->out.nxt);            /* bytes swapped */
  100.  
  101. /*
  102. *  if the port has some credit limit, use it instead of large
  103. *  window buffer.  Generally demanded by hardware limitations.
  104. */
  105.     if (p->credit < p->in.size)
  106.         p->tcpout.t.window = intswap(p->credit);
  107.     else
  108.         p->tcpout.t.window = intswap(p->in.size);    /* window size */
  109.  
  110. /*
  111. *  prepare pseudo-header for checksum
  112. */
  113.     p->tcps.tcplen = intswap(dlen+sizeof(TCPLAYER));
  114.     p->tcpout.t.check = 0;
  115.     p->tcpout.t.check = tcpcheck(&p->tcps,&p->tcpout.t,dlen+sizeof(struct tcph));
  116.  
  117.     p->out.lasttime = time(NULL);
  118.  
  119.     return(dlayersend(&p->tcpout,                                            /* BYU 2.4.15 */
  120.         (int) (sizeof(DLAYER)+sizeof(IPLAYER)+sizeof(TCPLAYER)+dlen),p->type));/* BYU 2.4.15 */
  121. } /* tcpsend */
  122.  
  123. /**********************************************************************/
  124. /*  checkmss
  125. *  Look at incoming SYN,ACK packet and check for the options field
  126. *  containing a TCP Maximum segment size option.  If it has one,
  127. *  then set the port's internal value to make sure that it never
  128. *  exceeds that segment size.
  129. */
  130. void checkmss
  131.   (
  132.     struct port *prt,
  133.     TCPKT *p,
  134.     int hlen
  135.   )
  136.     {
  137.     unsigned int i;
  138. /*
  139. *  check header for maximum segment size option
  140. */
  141.     if (hlen > 20 && p->x.options[0] == 2 && p->x.options[1] == 4) {
  142.         movebytes(&i,&p->x.options[2],2);    /* swapped value of maxseg */
  143.         i = intswap(i);
  144.         if (i < prt->sendsize)                /* we have our own limits too */
  145.             prt->sendsize = i;
  146.     }
  147. } /* checkmss */
  148.  
  149. /***************************************************************************/
  150. /*  ackcheck
  151. *   take an incoming packet and see if there is an ACK for the outgoing
  152. *   side.  Use that ACK to dequeue outgoing data.
  153. */
  154. int ackcheck
  155.   (
  156.     struct port *p,
  157.     TCPKT *t,
  158.     int pnum
  159.   )
  160.     {
  161.     uint32 ak;
  162.     int32 rttl;
  163.     int i;
  164.  
  165.     if ((t->t.flags & TRESET) && (t->t.seq == p->tcpout.t.ack)) {
  166.         netposterr(405);
  167.         p->state = SCLOSED;
  168.         netputuev(CONCLASS,CONCLOSE,pnum);
  169.         return(1);
  170.     }
  171.  
  172.     if (!(t->t.flags & TACK))                /* check ACK flag */
  173.         return(1);                             /* if no ACK, no go */
  174.  
  175.     p->out.size = intswap(t->t.window);    /* allowable transmission size */
  176.  
  177. /*
  178. *  rmqueue any bytes which have been ACKed, update p->out.nxt to the
  179. *  new next seq number for outgoing.  Update send window.
  180. *
  181. */
  182.     ak = longswap(t->t.ack);            /* other side's ACK */
  183. /*
  184. *  Need to add code to check for wrap-around of sequence space
  185. *  for ak.  ak - p->out.ack may be affected by sequence wraparound.
  186. *  If you have good, efficient code for this, please send it to me.
  187. *
  188. *  If ak is not increasing (above p->out.nxt) then we should assume
  189. *  that it is a duplicate packet or one of those stupid keepalive
  190. *  packets that 4.2 sends out.
  191. */
  192.     if (ak == p->out.nxt)                 /* BYU 2.4.15 */
  193.         p->out.lasttime = 0L;            /* BYU 2.4.15 */
  194.     else                                /* BYU 2.4.15 */
  195.     if (ak > p->out.nxt) {
  196.         rmqueue(&p->out,(int)(ak - p->out.ack));    /* take off of queue */
  197.         p->out.nxt = ak;
  198.         p->out.ack = ak;
  199. /*
  200. *  Check to see if this acked our most recent transmission.  If so, adjust
  201. *  the RTO value to reflect the newly measured RTT.  This formula reduces
  202. *  the RTO value so that it gradually approaches the most recent round
  203. *  trip measurement.  When a packet is retransmitted, this value is
  204. *  doubled (exponential backoff).
  205. */
  206.         rttl = time(NULL) - p->out.lasttime;
  207.         if (!p->out.contain &&             /* just now emptied queue */
  208.             rttl < (long)(MAXRTO) && p->rto >= MINRTO) {
  209.             i = (int)(rttl);
  210.             i = ((p->rto-MINRTO)*3 + i + 1) >> 2;    /* smoothing function */
  211.             p->rto = i+MINRTO;
  212.         }
  213.  
  214.         if (p->out.size > 0)
  215.             p->out.lasttime = 0L;            /* forces xmit */
  216.         return(0);
  217.     }
  218.     return(1);
  219. } /* ackcheck */
  220.  
  221. /***************************************************************************/
  222. /* checkfin
  223. *   Check the FIN bit of an incoming packet to see if the connection
  224. *   should be closing, ACK it if we need to.
  225. *   Half open connections immediately, automatically close.  We do
  226. *   not support them.  As soon as the incoming data is delivered, the
  227. *   connection will close.
  228. */
  229. void checkfin
  230.   (
  231.     struct port *prt,
  232.     TCPKT *pkt
  233.   )
  234.     {
  235.  
  236.     if (pkt->t.flags & TFIN) {        /* fin bit found */
  237.  
  238.         prt->in.nxt++;                /* count the FIN byte */
  239.         prt->state = SCWAIT;        /* close-wait */
  240.         prt->tcpout.t.ack = longswap(prt->in.nxt);    /* set ACK in packet */
  241.         prt->credit = 0;
  242.         prt->out.lasttime = 0L;        /* cause ACK to be sent */
  243.         netputuev(CONCLASS,CONCLOSE,pnum);
  244.  
  245. /*
  246. *   At this point, we know that we have received all data that the other
  247. *   side is allowed to send.  Some of that data may still be in the 
  248. *   incoming queue.  As soon as that queue empties, finish off the TCP
  249. *   close sequence.  We are not allowing the user to utilize a half-open
  250. *   connection, but we cannot close before the user has received all of
  251. *   the data from the incoming queue.
  252. */
  253.         if (!prt->in.contain) {                    /* data remaining? */
  254.             prt->tcpout.t.flags = TFIN | TACK;
  255.             tcpsend(prt,0);
  256.             prt->state = SLAST;
  257.         }
  258.     }
  259. } /* checkfin */
  260.  
  261. /***************************************************************************/
  262. /*  estab1986
  263. *   take a packet which has arrived for an established connection and
  264. *   put it where it belongs.
  265. */
  266. int estab1986
  267.   (
  268.     struct port *prt,
  269.     TCPKT *pkt,
  270.     int tlen,
  271.     int hlen
  272.   )
  273.     {
  274.     int dlen;
  275.     uint32 sq,want;
  276.  
  277.     dlen = tlen-hlen;
  278.     
  279. #ifdef OLDM
  280. /*  problem with old way is that dlen==0 is not checked to see if it is in
  281.   seq window */
  282.   
  283.     if (dlen <= 0) {                        /* only an ACK packet */
  284.         checkfin(prt,pkt);                    /* might still have FIN */
  285.         return(0);
  286.     }
  287. #endif
  288.  
  289. /*
  290. *  see if we want this packet, or is it a duplicate?
  291. */
  292.     sq = longswap(pkt->t.seq);
  293.     want = prt->in.nxt;
  294.  
  295.     if (sq != want) {                            /* we may want it, may not */
  296.  
  297.         if (sq < want && sq+dlen >= want) {      /* overlap */
  298.             hlen += want-sq;                    /* offset desired */
  299.             dlen -= want-sq;                    /* skip this much */
  300.         }
  301.         else {                                    /* tough it */
  302.             prt->out.lasttime = 0L;                /* make the ACK time out */
  303.             return(-1);
  304.         }
  305.     }
  306.     else if (dlen <= 0) {                        /* only an ACK packet */
  307.         checkfin(prt,pkt);                        /* might still have FIN */
  308.         return(0);
  309.     }
  310.  
  311. /*
  312. *  If we have room in the window, update the ACK field values
  313. */
  314.     if (prt->in.size >= dlen) {
  315.         prt->in.nxt += dlen;                /* new ack value */
  316.         prt->tcpout.t.ack = longswap(prt->in.nxt);
  317.         prt->in.size -= dlen;                /* new window size */
  318.  
  319.         prt->out.lasttime = 0L;                /* force timeout for ACK */
  320.  
  321.         enqueue(&prt->in,pkt->x.data+hlen-20,dlen);
  322.         netputuev(CONCLASS,CONDATA,pnum);    /* tell user about it */
  323.  
  324.         prt->in.lasttime = time(NULL);
  325.  
  326.     }
  327.  
  328.     else {                                    /* no room in input buffer */
  329.         prt->out.lasttime = 0L;                /* re-ack old sequence value */
  330.  
  331.     }
  332.  
  333. /* 
  334. *  Check the FIN bit to see if this connection is closing
  335. */
  336.     checkfin(prt,pkt);
  337.  
  338.     return(0);
  339. } /* estab1986 */
  340.  
  341. /**********************************************************************/
  342. /*  tcpdo
  343. *  Looking at the port structure for the destination port, deliver
  344. *  the incoming packet.
  345. */
  346. int tcpdo
  347.   (
  348.     struct port *prt,
  349.     TCPKT *p,
  350.     int tlen,
  351.     int hlen
  352.   )
  353.     {
  354.  
  355.     switch (prt->state) {
  356.  
  357.         case SLISTEN:                    /* waiting for remote connection */
  358.             if (p->t.flags & TSYN) {    /* receive SYN */
  359. /*
  360. *   remember anything important from the incoming TCP header 
  361. */
  362.                 prt->out.size = intswap(p->t.window);    /* credit window */
  363.                 prt->out.port = intswap(p->t.source);
  364.                 prt->in.nxt = longswap(p->t.seq) + 1;
  365. /*
  366. *  set the necessary fields in the outgoing TCP packet
  367. */
  368.                 prt->tcpout.t.dest = p->t.source;
  369.                 prt->tcpout.t.ack = longswap(prt->in.nxt);
  370.                 prt->tcpout.t.flags = TSYN | TACK;
  371.                 prt->tcpout.t.hlen = 24 << 2;
  372. /*
  373. *  note that the maxmimum segment size is installed by 'netlisten()'
  374. *  hence the header length is 24, not 20
  375. */
  376.                                 
  377. /*
  378. *  initialize all of the low-level transmission stuff (IP and lower)
  379. */
  380.                 movebytes(prt->tcps.dest,p->i.ipsource,4);
  381.                 movebytes(prt->tcpout.i.ipdest,p->i.ipsource,4);
  382.                 movebytes(prt->tcpout.d.dest,p->d.me,DADDLEN);
  383. #ifdef MAC
  384. /*
  385. *   look up address in the arp cache if using Atalk encapsulation
  386. */
  387.     if (!nnemac) {
  388.         unsigned char *pc;
  389.             pc = getdlayer(p->i.ipsource);
  390.             if (pc != NULL)
  391.                 movebytes(prt->tcpout.d.dest,pc,DADDLEN);
  392.             else
  393.                 return(0);        /* no hope this time */
  394.     }
  395. #endif
  396.  
  397.                 tcpsend(prt,4);
  398.                 prt->state = SSYNR;        /* syn received */
  399.             }
  400.             break;
  401.         case SSYNR:
  402.             if (!(p->t.flags & TACK)) {
  403.                 tcpsend(prt,4);
  404.                 break;                    /* not the right one */
  405.             }
  406.             prt->tcpout.t.hlen = 20 << 2;
  407.             prt->out.lasttime = time(NULL);            /* don't need response */
  408.             prt->out.nxt++;                            /* count SYN as sent */
  409.             prt->out.ack = longswap(p->t.ack);         /* starting ACK value */
  410.             prt->out.size = intswap(p->t.window);    /* allowed window */
  411.             prt->tcpout.t.flags = TACK;        /* starting ACK flag */
  412.             prt->state = SEST;                /* drop through to established */
  413.             netputevent(CONCLASS,CONOPEN,pnum);
  414.             checkmss(prt,p,hlen);            /* see if MSS option is there */
  415.  
  416.                                             /* fall through */
  417.         case SEST:
  418.             /* normal data transmission */
  419.             /*
  420.             *  check and accept a possible piggybacked ack
  421.             */
  422.             ackcheck(prt,p,pnum);
  423.  
  424.             estab1986(prt,p,tlen,hlen);
  425.             return(0);
  426.         case SSYNS:                /* check to see if it ACKS correctly */
  427.                                 /* remember that tcpout is pre-set-up */
  428.             if (p->t.flags & TACK) {        /* It is ACKING us */
  429.                 if (longswap(p->t.ack) != prt->out.nxt) {
  430.                     netposterr(401);
  431.                     return(1);
  432.                 }
  433.             }
  434.             if (p->t.flags & TRESET) {
  435.                 netposterr(507);
  436.                 prt->state = SCLOSED;
  437.                 netputuev(CONCLASS,CONCLOSE,pnum);
  438.                 return(1);
  439.             }
  440.             if (p->t.flags & TSYN) {            /* need to send ACK */
  441.                 prt->tcpout.t.flags = TACK;
  442.                 prt->in.nxt = longswap(p->t.seq) + 1;
  443.                 prt->tcpout.t.ack = longswap(prt->in.nxt);
  444.                 prt->out.ack = longswap(p->t.ack);
  445.                 prt->out.size = intswap(p->t.window);    /* credit window */
  446.                 prt->out.lasttime = 0L;
  447.                 if (p->t.flags & TACK) {
  448.                     prt->state = SEST;
  449.                     netputevent(CONCLASS,CONOPEN,pnum);
  450.                     checkmss(prt,p,hlen);
  451.                 }
  452.                 else
  453.                     prt->state = SSYNR;        /* syn received */
  454.             }
  455.             break;
  456.         case SCWAIT:
  457.             ackcheck(prt,p,pnum);
  458.             if (!prt->in.contain) {
  459.                 prt->tcpout.t.flags = TFIN | TACK;
  460.                 prt->out.lasttime = 0L;
  461.                 prt->state = SLAST;
  462.             }
  463.             break;
  464.         case SLAST:
  465.             /* check ack of FIN, or reset to see if we are done */
  466.             if ((p->t.flags & TRESET) || (longswap(p->t.ack) == prt->out.nxt+1))
  467.                 prt->state = SCLOSED;
  468.             break;
  469.         case SFW1:                            /* waiting for ACK of FIN */
  470.                                             /* throw away data */
  471.             prt->in.nxt = longswap(p->t.seq)+tlen-hlen;
  472.             if (p->t.flags & TRESET)
  473.                 prt->state = SCLOSED;
  474.             else if (longswap(p->t.ack) != prt->out.nxt+1) {
  475.                 if (p->t.flags & TFIN) {    /* got FIN, no ACK for mine */
  476.                     prt->in.nxt++;                /* account for FIN byte */
  477.                     prt->tcpout.t.ack = longswap(prt->in.nxt);
  478.                     prt->tcpout.t.flags = TACK;    /* final byte has no FIN flag */
  479.                     prt->out.lasttime = 0L;        /* cause last ACK to be sent */
  480.                     prt->state = SCLOSING;
  481.                 }
  482.                 else {
  483.                     prt->tcpout.t.ack = longswap(prt->in.nxt);
  484.                     prt->tcpout.t.flags = TACK | TFIN;
  485.                     prt->out.lasttime = 0L;
  486.                 }
  487.             }
  488.             else if (p->t.flags & TFIN) {    /* ACK and FIN */
  489.                 prt->in.nxt++;                /* account for his FIN flag */
  490.                 prt->out.nxt++;                /* account for my FIN */
  491.                 prt->tcpout.t.ack = longswap(prt->in.nxt);
  492.                 prt->tcpout.t.flags = TACK;    /* final byte has no FIN flag */
  493.                 prt->out.lasttime = 0L;        /* cause last ACK to be sent */
  494.                 prt->state = STWAIT;        /* we are done */
  495.             }
  496.             else {                            /* got ACK, no FIN */
  497.                 prt->out.nxt++;                /* account for my FIN byte */
  498.                 prt->tcpout.t.flags = TACK;    /* final pkt has no FIN flag */
  499.                 prt->state = SFW2;
  500.             }
  501.             break;
  502.         case SFW2:                                /* want FIN */
  503.             prt->in.nxt = longswap(p->t.seq)+tlen-hlen;
  504.             if (p->t.flags & TRESET)
  505.                 prt->state = SCLOSED;
  506.             else if (p->t.flags & TFIN) {        /* we got FIN */
  507.                 prt->in.nxt++;                    /* count his FIN byte */
  508.                 prt->tcpout.t.ack = longswap(prt->in.nxt);
  509.                 prt->out.lasttime = 0L;        /* cause last ACK to be sent */
  510.                 prt->state = STWAIT;
  511.             }
  512.             break;
  513.         case SCLOSING:                        /* want ACK of FIN */
  514.             if (p->t.flags & TRESET)
  515.                 prt->state = SCLOSED;
  516.             else if (!ackcheck(prt,p,pnum)) {
  517.                 prt->out.nxt++;                /* account for my FIN byte */
  518.                 prt->state = STWAIT;        /* time-wait state next */
  519.             }
  520.             break;
  521.         case STWAIT:                        /* ack FIN again? */
  522.             if (p->t.flags & TRESET)
  523.                 prt->state = SCLOSED;
  524.             if (p->t.flags & TFIN)             /* only if he wants it */
  525.                 prt->out.lasttime = 0L;
  526.             if (prt->out.lasttime && 
  527.                 (prt->out.lasttime + WAITTIME < time(NULL))) 
  528.                 prt->state = SCLOSED;
  529.             break;            
  530.         case SCLOSED:
  531.             prt->in.port = prt->out.port = 0;
  532.             break;
  533.         default:
  534.             netposterr(403);            /* unknown tcp state */
  535.             break;
  536.     }
  537.     return(0);
  538. } /* tcpdo */
  539.  
  540. /**********************************************************************/
  541. /* tcpreset
  542. *  Send a reset packet back to sender
  543. *  Use the packet which just came in as a template to return to
  544. *  sender.  Fill in all of the fields necessary and dlayersend it back.
  545. */
  546. int tcpreset
  547.   (
  548.     TCPKT *t,                        /* BYU 2.4.15 */
  549.     short fromSLIP                    /* BYU 2.4.15 */
  550.   )
  551.     {
  552.     uint tport;
  553.     struct pseudotcp xxx;
  554.  
  555.     if (t->t.flags & TRESET)        /* don't reset a reset */
  556.         return(1);
  557.  
  558. /*
  559. *  swap TCP layer portions for sending back
  560. */
  561.     if (t->t.flags & TACK) {
  562.         t->t.seq = t->t.ack;        /* ack becomes next seq # */
  563.         t->t.ack = 0L;                /* ack # is 0 */
  564.         t->t.flags = TRESET;        /* BYU 2.4.16 */
  565.     }
  566.     else {
  567. #if 1                                                    /* BYU 2.4.16 */
  568.         t->t.ack = longswap(longswap(t->t.seq) + 1);    /* BYU 2.4.16 */
  569.         t->t.flags = TACK | TRESET;                        /* BYU 2.4.16 */
  570. #else                                                    /* BYU 2.4.16 */
  571.         t->t.ack = longswap(longswap(t->t.seq)+t->i.tlen-sizeof(IPLAYER));
  572. #endif                                                    /* BYU 2.4.16 */
  573.         t->t.seq = 0L;
  574.     }
  575.  
  576.     t->t.flags = TRESET;
  577.     tport = t->t.source;                    /* swap port #'s */
  578.     t->t.source = t->t.dest;
  579.     t->t.dest = tport;
  580.     t->t.hlen = 80;                /* header len */        /* BYU 2.4.16 - was "20 << 2" */
  581.     t->t.window = 0;
  582.  
  583. /*
  584. *  create pseudo header for checksum
  585. */
  586.     xxx.z = 0;
  587.     xxx.proto = t->i.protocol;
  588.     xxx.tcplen = intswap(20);
  589.     movebytes(xxx.source,t->i.ipsource,4);
  590.     movebytes(xxx.dest,t->i.ipdest,4);
  591.  
  592.     t->t.check = 0;    
  593.     t->t.check = tcpcheck(&xxx,&t->t,sizeof(struct tcph));
  594. /*
  595. *  IP and data link layers
  596. */    
  597.     movebytes(t->i.ipdest,t->i.ipsource,4);  /* machine it came from */
  598.     if (fromSLIP)                                    /* BYU 2.4.15 */
  599.         movebytes(t->i.ipsource,SLIP_ip_number,4);    /* BYU 2.4.15 */
  600.     else {                                            /* BYU 2.4.15 */
  601.         movebytes(t->i.ipsource,nnipnum,4);            /* BYU 2.4.15 */
  602.     }                                                /* BYU 2.4.15 */
  603.     t->i.tlen = intswap(sizeof(IPLAYER)+sizeof(TCPLAYER));
  604.     t->i.ident = nnipident++;
  605.     t->i.ttl = 30;
  606.     t->i.check = 0;
  607.     t->i.check = ipcheck(&t->i,10);
  608.  
  609.     movebytes(t->d.dest,t->d.me,DADDLEN);    /* data link address */
  610.     movebytes(t->d.me,blankd.me,DADDLEN);    /* my address */
  611.  
  612.     return(dlayersend(t,(int) (sizeof(DLAYER)+sizeof(IPLAYER)+sizeof(TCPLAYER)),fromSLIP));    /* BYU 2.4.15 */
  613.  
  614. } /* tcpreset */
  615.  
  616. /************************************************************************
  617. *  tcpinterpret
  618. *  This is called when a packet comes in, passes IP checksumming and is
  619. *  of the TCP protocol type.  Check and see if we are expecting it and
  620. *  where the data should go.
  621. */
  622. int tcpinterpret
  623.   (
  624.     TCPKT *p,
  625.     int tlen,                            /* BYU 2.4.15 */
  626.     short fromSLIP                        /* BYU 2.4.15 */
  627.   )
  628.     {
  629.     uint i,myport,hlen,hisport;
  630.     struct port *prt;
  631.     
  632. /*
  633. *  checksum
  634. *    First, fill the pseudo header with its fields, then run our
  635. *  checksum to confirm it.
  636. *
  637. */
  638.     if (p->t.check) {
  639.         movebytes(tcps.source,p->i.ipsource,8);  /* move both addresses */
  640.         tcps.z = 0;
  641.         tcps.proto = p->i.protocol;
  642.  
  643.         tcps.tcplen = intswap(tlen);            /* byte-swapped length */
  644.  
  645.         if (tcpcheck(&tcps,&p->t,tlen)) {    /* compute checksum */
  646.             netposterr(400);
  647.             return(2);
  648.         }
  649.     }
  650.  
  651. /*
  652. *  find the port which is associated with the incoming packet
  653. *  First try open connections, then try listeners
  654. */
  655.     myport = intswap(p->t.dest);
  656.     hisport = intswap(p->t.source);
  657.     hlen = p->t.hlen >> 2;                /* bytes offset to data */
  658.  
  659.  
  660.     for (i=0; i<NPORTS; i++) {
  661.  
  662.         prt = portlist[i];
  663.  
  664.         if (prt != NULL && prt->in.port == myport && prt->out.port == hisport) {
  665.             pnum = i;
  666.             prt->type = fromSLIP;                    /* BYU 2.4.15 */
  667.             if (fromSLIP)                            /* BYU 2.4.16 */
  668.                 porttype[pnum] = NCSA_PORT_TYPE;    /* BYU 2.4.16 */
  669.             return(tcpdo(prt,p,tlen,hlen));
  670.         }
  671.  
  672.     }
  673.  
  674. /*
  675. *  check to see if the incoming packet should go to a listener
  676. */
  677.  
  678.     for (i=0; i < NPORTS; i++) {
  679.         prt = portlist[i];
  680.  
  681.         if (prt != NULL && !prt->out.port && 
  682.             prt->in.port == myport && (p->t.flags & TSYN)) {
  683.             pnum = i;
  684.             prt->type = fromSLIP;                                    /* BYU 2.4.15 */
  685.             if (fromSLIP) {                                            /* BYU 2.4.15 */
  686.                 memmove(prt->tcpout.i.ipsource,SLIP_ip_number,4);    /* BYU 2.4.15 */
  687.                 memmove(prt->tcps.source,SLIP_ip_number,4);            /* BYU 2.4.15 */
  688.                 porttype[pnum] = NCSA_PORT_TYPE;                    /* BYU 2.4.16 */
  689.             }
  690.             return(tcpdo(prt,p,tlen,hlen));
  691.             }
  692.  
  693.     }
  694.  
  695. /*
  696. *  no matching port was found to handle this packet, reject it
  697. */
  698.  
  699.         tcpreset(p,fromSLIP);        /* BYU 2.4.15 - tell them they are crazy */
  700.         if (!(p->t.flags & TSYN))    /* no error message if it is a SYN */
  701.             netposterr(407);            /* invalid port for incoming packet */
  702.  
  703.         return(1);                    /* no port matches */
  704.  
  705. } /* tcpinterpret */
  706.